package eval

import (
	"showen7/eval"
	"showen7/inter"
	"showen7/lex"
	"showen7/parse"
	"testing"
)

func TestLessThan(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(< 1 2)", "#t"},
		{"(< 1.2 1)", "#f"},
		{"(< 1 2 3)", "#t"},
		{"(< 1 3 2)", "#f"},
		{"(< 5 5)", "#f"},
		{"(< 1/2 3/4)", "#t"},
		{"(< 3/4 1/2)", "#f"},
		{"(< 1 1.5 2)", "#t"},
		{"(< 2 1.5 1)", "#f"},
		{"(< -5 -3 -1)", "#t"},
		{"(< -1 -3 -5)", "#f"},
		{"(< 0 0)", "#f"},
		// Mixed number type tests
		{"(< 1 3/2 2)", "#t"},
		{"(< 1 1.5 3/2)", "#f"}, // 1.5 and 3/2 are equal
		{"(< 1/2 0.75 1)", "#t"},
		{"(< 2 5/2 3.14 4)", "#t"},
		{"(< 10 9.999)", "#f"},
		{"(< 1.0 2 5/2)", "#t"},
		{"(< 3 3.0)", "#f"}, // Equal values
		{"(< 3.0 3)", "#f"}, // Equal values, different order
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		var obj inter.Object
		obj, err = eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}
		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestLessThanOrEqual(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(<= 1 2)", "#t"},
		{"(<= 1.2 1)", "#f"},
		{"(<= 1 2 3)", "#t"},
		{"(<= 1 3 2)", "#f"},
		{"(<= 5 5)", "#t"}, // Equal values should return #t
		{"(<= 1/2 3/4)", "#t"},
		{"(<= 3/4 1/2)", "#f"},
		{"(<= 1 1.5 2)", "#t"},
		{"(<= 2 1.5 1)", "#f"},
		{"(<= -5 -3 -1)", "#t"},
		{"(<= -1 -3 -5)", "#f"},
		{"(<= 0 0)", "#t"}, // Equal values should return #t
		// Mixed number type tests
		{"(<= 1 3/2 2)", "#t"},
		{"(<= 1 1.5 3/2)", "#t"}, // 1.5 and 3/2 are equal
		{"(<= 1/2 0.75 1)", "#t"},
		{"(<= 2 5/2 3.14 4)", "#t"},
		{"(<= 10 9.999)", "#f"},
		{"(<= 1.0 2 5/2)", "#t"},
		{"(<= 3 3.0)", "#t"}, // Equal values
		{"(<= 3.0 3)", "#t"}, // Equal values, different order
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		var obj inter.Object
		obj, err = eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}
		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestGreaterThanOrEqual(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(>= 2 1)", "#t"},
		{"(>= 1 1.2)", "#f"},
		{"(>= 3 2 1)", "#t"},
		{"(>= 2 3 1)", "#f"},
		{"(>= 5 5)", "#t"}, // Equal values should return #t
		{"(>= 3/4 1/2)", "#t"},
		{"(>= 1/2 3/4)", "#f"},
		{"(>= 2 1.5 1)", "#t"},
		{"(>= 1 1.5 2)", "#f"},
		{"(>= -1 -3 -5)", "#t"},
		{"(>= -5 -3 -1)", "#f"},
		{"(>= 0 0)", "#t"}, // Equal values should return #t
		// Mixed number type tests
		{"(>= 2 3/2 1)", "#t"},
		{"(>= 3/2 1.5 1)", "#t"}, // 1.5 and 3/2 are equal
		{"(>= 1 0.75 1/2)", "#t"},
		{"(>= 4 3.14 5/2 2)", "#t"},
		{"(>= 9.999 10)", "#f"},
		{"(>= 5/2 2 1.0)", "#t"},
		{"(>= 3 3.0)", "#t"}, // Equal values
		{"(>= 3.0 3)", "#t"}, // Equal values, different order
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		var obj inter.Object
		obj, err = eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}
		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestGreaterThan(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(> 2 1)", "#t"},
		{"(> 1 1.2)", "#f"},
		{"(> 3 2 1)", "#t"},
		{"(> 2 3 1)", "#f"},
		{"(> 5 5)", "#f"}, // Equal values should return #f
		{"(> 3/4 1/2)", "#t"},
		{"(> 1/2 3/4)", "#f"},
		{"(> 2 1.5 1)", "#t"},
		{"(> 1 1.5 2)", "#f"},
		{"(> -1 -3 -5)", "#t"},
		{"(> -5 -3 -1)", "#f"},
		{"(> 0 0)", "#f"}, // Equal values should return #f
		// Mixed number type tests
		{"(> 2 3/2 1)", "#t"},
		{"(> 3/2 1.5 1)", "#f"}, // 1.5 and 3/2 are equal
		{"(> 1 0.75 1/2)", "#t"},
		{"(> 4 3.14 5/2 2)", "#t"},
		{"(> 9.999 10)", "#f"},
		{"(> 5/2 2 1.0)", "#t"},
		{"(> 3 3.0)", "#f"}, // Equal values
		{"(> 3.0 3)", "#f"}, // Equal values, different order
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		var obj inter.Object
		obj, err = eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}
		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestEqual(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(= 2 2)", "#t"},
		{"(= 1 1.0)", "#t"},
		{"(= 3 2 1)", "#f"},
		{"(= 2 3 1)", "#f"},
		{"(= 5 5)", "#t"}, // Equal values should return #t
		{"(= 3/4 0.75)", "#t"},
		{"(= 1/2 3/4)", "#f"},
		{"(= 2 1.5 1)", "#f"},
		{"(= 1 1.5 2)", "#f"},
		{"(= -1 -1)", "#t"},
		{"(= -5 -3 -1)", "#f"},
		{"(= 0 0)", "#t"}, // Equal values should return #t
		// Mixed number type tests
		{"(= 2 3/2 1)", "#f"},
		{"(= 3/2 1.5)", "#t"}, // 1.5 and 3/2 are equal
		{"(= 1 0.75 1/2)", "#f"},
		{"(= 4 4.0 8/2)", "#t"},
		{"(= 9.999 10)", "#f"},
		{"(= 5/2 2.5 1.0)", "#f"},
		{"(= 3 3.0)", "#t"}, // Equal values
		{"(= 3.0 3)", "#t"}, // Equal values, different order
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		var obj inter.Object
		obj, err = eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}
		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestEqualWithComplexNumbers(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(= 1+2i 1+2i)", "#t"},
		{"(= 1+2i 2+3i)", "#f"},
		{"(= 3+4i 3+4i 2+1i)", "#f"},
		{"(= 3+4i 3+4i 3+4i)", "#t"},
		{"(= +i +i)", "#t"},
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		var obj inter.Object
		obj, err = eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}
		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestLessThanWithSingleArgument(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(< 5)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((< 5)) = %v, want #t", obj.Inspect())
	}
}

func TestLessThanOrEqualWithSingleArgument(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(<= 5)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((<= 5)) = %v, want #t", obj.Inspect())
	}
}

func TestGreaterThanOrEqualWithSingleArgument(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(>= 5)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((>= 5)) = %v, want #t", obj.Inspect())
	}
}

func TestGreaterThanWithSingleArgument(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(> 5)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((> 5)) = %v, want #t", obj.Inspect())
	}
}

func TestEqualWithSingleArgument(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(= 5)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((= 5)) = %v, want #t", obj.Inspect())
	}
}

func TestLessThanWithComplexNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(< 1+2i 2+3i)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for complex numbers, but got none")
	}
}

func TestLessThanOrEqualWithComplexNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(<= 1+2i 2+3i)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for complex numbers, but got none")
	}
}

func TestGreaterThanOrEqualWithComplexNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(>= 1+2i 2+3i)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for complex numbers, but got none")
	}
}

func TestGreaterThanWithComplexNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(> 1+2i 2+3i)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for complex numbers, but got none")
	}
}

func TestLessThanWithNonNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(< 1 \"string\")")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for non-numbers, but got none")
	}
}

func TestLessThanOrEqualWithNonNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(<= 1 \"string\")")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for non-numbers, but got none")
	}
}

func TestGreaterThanOrEqualWithNonNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(>= 1 \"string\")")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for non-numbers, but got none")
	}
}

func TestGreaterThanWithNonNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(> 1 \"string\")")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for non-numbers, but got none")
	}
}

func TestEqualWithNonNumbers(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(= 1 \"string\")")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	_, err = eval.EvalExpression(expr, env)
	if err == nil {
		t.Errorf("Expected error for non-numbers, but got none")
	}
}

func TestLessThanWithNoArguments(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(<)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((<)) = %v, want #t", obj.Inspect())
	}
}

func TestLessThanOrEqualWithNoArguments(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(<=)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((<=)) = %v, want #t", obj.Inspect())
	}
}

func TestGreaterThanOrEqualWithNoArguments(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(>=)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((>=)) = %v, want #t", obj.Inspect())
	}
}

func TestGreaterThanWithNoArguments(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(>)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((>)) = %v, want #t", obj.Inspect())
	}
}

func TestEqualWithNoArguments(t *testing.T) {
	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	lexer := lex.NewLexer("(=)")
	tokens := lexer.ReadTokens()
	parser := parse.NewParser(tokens)
	expr, err := parser.ParseExpression()
	if err != nil {
		t.Fatalf("parser.ParseExpression() error = %v", err)
	}

	obj, err := eval.EvalExpression(expr, env)
	if err != nil {
		t.Fatalf("EvalExpression() error = %v", err)
	}

	if obj.Inspect() != "#t" {
		t.Errorf("EvalExpression((=)) = %v, want #t", obj.Inspect())
	}
}

func TestLessThanMixedTypes(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(< 1 2.0)", "#t"},
		{"(< 2.0 1)", "#f"},
		{"(< 1/2 0.5)", "#f"}, // Equal values
		{"(< 0.5 1/2)", "#f"}, // Equal values, different order
		{"(< 1/4 0.3)", "#t"}, // 1/4 (0.25) is less than 0.3
		{"(< 0.3 1/4)", "#f"}, // 0.3 is greater than 1/4 (0.25)
		{"(< 1 5/4 1.5 2)", "#t"},
		{"(< 3 3.14159 22/7)", "#t"},
		{"(< 2 2.0 2.0)", "#f"}, // Contains equal values
		{"(< 1 2 3 3)", "#f"},   // Contains equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestLessThanOrEqualMixedTypes(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(<= 1 2.0)", "#t"},
		{"(<= 2.0 1)", "#f"},
		{"(<= 1/2 0.5)", "#t"}, // Equal values
		{"(<= 0.5 1/2)", "#t"}, // Equal values, different order
		{"(<= 1/4 0.3)", "#t"}, // 1/4 (0.25) is less than 0.3
		{"(<= 0.3 1/4)", "#f"}, // 0.3 is greater than 1/4 (0.25)
		{"(<= 1 5/4 1.5 2)", "#t"},
		{"(<= 3 3.14159 22/7)", "#t"},
		{"(<= 2 2.0 2.0)", "#t"}, // Contains equal values
		{"(<= 1 2 3 3)", "#t"},   // Contains equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestGreaterThanOrEqualMixedTypes(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(>= 2.0 1)", "#t"},
		{"(>= 1 2.0)", "#f"},
		{"(>= 0.5 1/2)", "#t"}, // Equal values
		{"(>= 1/2 0.5)", "#t"}, // Equal values, different order
		{"(>= 0.3 1/4)", "#t"}, // 0.3 is greater than 1/4 (0.25)
		{"(>= 1/4 0.3)", "#f"}, // 1/4 (0.25) is less than 0.3
		{"(>= 2 1.5 1)", "#t"},
		{"(>= 22/7 3.14159 3)", "#t"},
		{"(>= 2.0 2 2.0)", "#t"}, // Contains equal values
		{"(>= 3 3 2 1)", "#t"},   // Contains equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestGreaterThanMixedTypes(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(> 2.0 1)", "#t"},
		{"(> 1 2.0)", "#f"},
		{"(> 0.5 1/2)", "#f"}, // Equal values
		{"(> 1/2 0.5)", "#f"}, // Equal values, different order
		{"(> 0.3 1/4)", "#t"}, // 0.3 is greater than 1/4 (0.25)
		{"(> 1/4 0.3)", "#f"}, // 1/4 (0.25) is less than 0.3
		{"(> 2 1.5 1)", "#t"},
		{"(> 22/7 3.14159 3)", "#t"},
		{"(> 2.0 2 2.0)", "#f"}, // Contains equal values
		{"(> 3 3 2 1)", "#f"},   // Contains equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestEqualMixedTypes(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		{"(= 2.0 2)", "#t"},
		{"(= 1 2.0)", "#f"},
		{"(= 0.5 1/2)", "#t"},  // Equal values
		{"(= 1/2 0.5)", "#t"},  // Equal values, different order
		{"(= 0.3 1/4)", "#f"},  // 0.3 is greater than 1/4 (0.25)
		{"(= 1/4 0.25)", "#t"}, // Equal values
		{"(= 2 2.0 2)", "#t"},
		{"(= 22/7 3.14159)", "#f"},
		{"(= 2.0 2 2.0)", "#t"}, // All equal values
		{"(= 3 3 2 1)", "#f"},   // Contains different values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestLessThanBigIntegerAndRational(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		// Test with large integers that become BigInteger
		{"(< 123456789012345 123456789012346)", "#t"},
		{"(< 123456789012346 123456789012345)", "#f"},
		// Test with rationals that have big integer components
		{"(< 123456789012345/2 123456789012346/2)", "#t"},
		{"(< 999999999999999999999/1000000000000000000000 1000000000000000000001/1000000000000000000000)", "#t"},
		// Mixed BigInteger and Rational(BigInteger/BigInteger)
		{"(< 61728394506172 61728394506173)", "#t"}, // 123456789012345/2 = 61728394506172.5, which becomes 61728394506172
		{"(< 61728394506173 61728394506172)", "#f"},
		// Multiple argument sequences with big numbers
		{"(< 100000000000000 100000000000001 100000000000002)", "#t"},
		{"(< 100000000000000 100000000000000)", "#f"},
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestLessThanOrEqualBigIntegerAndRational(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		// Test with large integers that become BigInteger
		{"(<= 123456789012345 123456789012346)", "#t"},
		{"(<= 123456789012346 123456789012345)", "#f"},
		{"(<= 123456789012345 123456789012345)", "#t"}, // Equal values
		// Test with rationals that have big integer components
		{"(<= 123456789012345/2 123456789012346/2)", "#t"},
		{"(<= 999999999999999999999/1000000000000000000000 1000000000000000000001/1000000000000000000000)", "#t"},
		// Mixed BigInteger and Rational(BigInteger/BigInteger)
		{"(<= 61728394506172 61728394506173)", "#t"}, // 123456789012345/2 = 61728394506172.5, which becomes 61728394506172
		{"(<= 61728394506173 61728394506172)", "#f"},
		{"(<= 61728394506173 61728394506173)", "#t"}, // Equal values
		// Multiple argument sequences with big numbers
		{"(<= 100000000000000 100000000000001 100000000000002)", "#t"},
		{"(<= 100000000000000 100000000000000 100000000000000)", "#t"}, // All equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestGreaterThanOrEqualBigIntegerAndRational(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		// Test with large integers that become BigInteger
		{"(>= 123456789012346 123456789012345)", "#t"},
		{"(>= 123456789012345 123456789012346)", "#f"},
		{"(>= 123456789012345 123456789012345)", "#t"}, // Equal values
		// Test with rationals that have big integer components
		{"(>= 123456789012346/2 123456789012345/2)", "#t"},
		{"(>= 1000000000000000000001/1000000000000000000000 999999999999999999999/1000000000000000000000)", "#t"},
		// Mixed BigInteger and Rational(BigInteger/BigInteger)
		{"(>= 61728394506173 61728394506172)", "#t"}, // 123456789012346/2 = 61728394506173
		{"(>= 61728394506172 61728394506173)", "#f"},
		{"(>= 61728394506173 61728394506173)", "#t"}, // Equal values
		// Multiple argument sequences with big numbers
		{"(>= 100000000000002 100000000000001 100000000000000)", "#t"},
		{"(>= 100000000000000 100000000000000 100000000000000)", "#t"}, // All equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestGreaterThanBigIntegerAndRational(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		// Test with large integers that become BigInteger
		{"(> 123456789012346 123456789012345)", "#t"},
		{"(> 123456789012345 123456789012346)", "#f"},
		{"(> 123456789012345 123456789012345)", "#f"}, // Equal values
		// Test with rationals that have big integer components
		{"(> 123456789012346/2 123456789012345/2)", "#t"},
		{"(> 1000000000000000000001/1000000000000000000000 999999999999999999999/1000000000000000000000)", "#t"},
		// Mixed BigInteger and Rational(BigInteger/BigInteger)
		{"(> 61728394506173 61728394506172)", "#t"}, // 123456789012346/2 = 61728394506173
		{"(> 61728394506172 61728394506173)", "#f"},
		{"(> 61728394506173 61728394506173)", "#f"}, // Equal values
		// Multiple argument sequences with big numbers
		{"(> 100000000000002 100000000000001 100000000000000)", "#t"},
		{"(> 100000000000000 100000000000000 100000000000000)", "#f"}, // All equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}

func TestEqualBigIntegerAndRational(t *testing.T) {
	tests := []struct {
		input string
		want  string
	}{
		// Test with large integers that become BigInteger
		{"(= 123456789012346 123456789012346)", "#t"},
		{"(= 123456789012345 123456789012346)", "#f"},
		{"(= 123456789012345 123456789012345)", "#t"}, // Equal values
		// Test with rationals that have big integer components
		{"(= 123456789012346/2 61728394506173)", "#t"},
		{"(= 1000000000000000000000/1000000000000000000000 1)", "#t"},
		// Mixed BigInteger and Rational(BigInteger/BigInteger)
		{"(= 61728394506173 61728394506173)", "#t"}, // 123456789012346/2 = 61728394506173
		{"(= 61728394506172 61728394506173)", "#f"},
		{"(= 61728394506173 61728394506173 61728394506173)", "#t"}, // Equal values
		// Multiple argument sequences with big numbers
		{"(= 100000000000000 100000000000000 100000000000000)", "#t"}, // All equal values
	}

	env := inter.NewEnvironment()
	eval.RegisterBuiltinProcedures(env)

	for _, tt := range tests {
		lexer := lex.NewLexer(tt.input)
		tokens := lexer.ReadTokens()
		parser := parse.NewParser(tokens)
		expr, err := parser.ParseExpression()
		if err != nil {
			t.Fatalf("parser.ParseExpression() error = %v", err)
		}

		obj, err := eval.EvalExpression(expr, env)
		if err != nil {
			t.Fatalf("EvalExpression() error = %v", err)
		}

		if obj.Inspect() != tt.want {
			t.Errorf("EvalExpression(%s) = %v, want %v", tt.input, obj.Inspect(), tt.want)
		}
	}
}
